package com.hundsun.epay.autosimu.config.xml;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.hundsun.epay.autosimu.config.Configuration;
import com.hundsun.epay.autosimu.exception.XmlParseException;

public class ConfiguratioinParser {
	private List<String> warning;
	private List<String> parseErrors;
	private Properties extraProperties;
	
	public ConfiguratioinParser(List<String> warning) {
		this(warning, null);
	}

	public ConfiguratioinParser(List<String> warning, Properties extraProperties) {
		if(warning == null){
			warning = new ArrayList<String>();
		}else{
			this.warning = warning;
		}
		this.extraProperties = extraProperties;
		this.parseErrors = new ArrayList<String>();
	}
	
	public Configuration parseConfiguration(File file) throws IOException, XmlParseException{
		FileReader fr = new FileReader(file);
		return parseConfiguration(fr);
	}
	
	public Configuration parseConfiguration(InputStream stream) throws IOException, XmlParseException{
		InputSource is = new InputSource(stream);
		return parseConfiguration(is);
	}
	
	public Configuration parseConfiguration(Reader reader) throws IOException, XmlParseException{
		InputSource is = new InputSource(reader);
		return parseConfiguration(is);
	}
	
	private Configuration parseConfiguration(InputSource is) throws IOException, XmlParseException{
		this.parseErrors.clear();
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setValidating(false);
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			ParserErrorHandler handler = new ParserErrorHandler(warning, parseErrors);
			builder.setErrorHandler(handler);
			builder.setEntityResolver(new DefaultHandler());
			Document document = null;
			try {
				document = builder.parse(is);
			} catch (SAXException e) {
				if(e.getException() == null){
					this.parseErrors.add(e.getMessage());
				}else{
					this.parseErrors.add(e.getException().getMessage());
				}
			}
			if(parseErrors.size() > 0){
				throw new XmlParseException(parseErrors);
			}
			Configuration config;
			Element rootNode = document.getDocumentElement();
			if(rootNode.getNodeType() == Node.ELEMENT_NODE){
				config = parseAutoSimuConfiguration(rootNode);
			}else{
				throw new XmlParseException("This is not a simu Generator Configuration File");
			}
			if(parseErrors.size() > 0){
				throw new XmlParseException(parseErrors);
			}
			return config;
		} catch (ParserConfigurationException e) {
			this.parseErrors.add(e.getMessage());
			throw new XmlParseException(parseErrors);
		}
	}
	
	private Configuration parseAutoSimuConfiguration(Element rootNode) throws XmlParseException{
		AutoSimuGeneratorConfigurationParser parser = new AutoSimuGeneratorConfigurationParser(extraProperties);
		return parser.parseConfiguration(rootNode);
	}
}
